﻿using System;
using System.Collections.Generic;
using System.Text;
using Mogre;
using MogreNewt;

namespace AplikacjaOgre
{
    class Player : Object
    {

        #region Zmienne profilu postaci

        public String MeshName;
        public float BodyMass;
        public float WalkSpeed;
        public Vector3 BodyScaleFactor;
        public Vector3 HeadOffset;

        #endregion

        #region Zmienne węzła sceny

        public Entity Entity;
        public SceneNode Node;
        public Body Body;

        #endregion

        #region Zmienne aktualnego stanu postaci

        public PlayerState PlayerState;

        public Quaternion Orientation;
        public Vector3 Velocity;

        #endregion

        #region Konstruktor oraz podstawowe funkcje

        public Player(String MeshName, float BodyMass, float WalkSpeed, Vector3 BodyScaleFactor, Vector3 HeadOffset)
        {
            this.MeshName = MeshName;
            this.BodyMass = BodyMass;
            this.WalkSpeed = WalkSpeed;
            this.BodyScaleFactor = BodyScaleFactor;
            this.HeadOffset = HeadOffset;

            Orientation = Quaternion.IDENTITY;

            Entity = Game.Instance.SceneManager.CreateEntity(MeshName);
            Node = Game.Instance.SceneManager.RootSceneNode.CreateChildSceneNode();
            Node.SetScale(BodyScaleFactor);
            Node.AttachObject(Entity);

            Vector3 size = Entity.BoundingBox.HalfSize * BodyScaleFactor;
            ConvexCollision collision = new MogreNewt.CollisionPrimitives.Capsule(Game.Instance.NewtonWorld, System.Math.Min(size.x, size.z), size.y * 2, Vector3.UNIT_X.GetRotationTo(Vector3.UNIT_Y), Game.Instance.getUniqueBodyId());

            Vector3 inertia;
            Vector3 offset;

            collision.CalculateInertialMatrix(out inertia, out offset);
            inertia *= BodyMass;

            Body = new Body(Game.Instance.NewtonWorld, collision, true);
            Body.AttachNode(Node);
            Body.SetMassMatrix(BodyMass, inertia);
            Body.AutoSleep = false;

            Body.Transformed += BodyTransformCallback;
            Body.ForceCallback += BodyForceCallback;

            Joint UpVEctor = new MogreNewt.BasicJoints.UpVector(Game.Instance.NewtonWorld, Body, Vector3.UNIT_Y);

            collision.Dispose();
        }

        public void SetPosition(Vector3 position)
        {
            Body.SetPositionOrientation(position, Orientation);
        }

        override public void Update()
        {
            //AnimationState idle = Entity.GetAnimationState("Dance");
            //AnimationState walk = Entity.GetAnimationState("RunBase");

            switch (PlayerState)
            {
                case PlayerState.IDLE:

                    Velocity = Vector3.ZERO;
                    //walk.Enabled = false;
                    //idle.Enabled = false;
                    //idle.Loop = true;
                    //idle.AddTime(1.0f / 90.0f);
                    break;

                case PlayerState.WALK:

                    Velocity = Orientation * Vector3.UNIT_Z * WalkSpeed;
                    //idle.Enabled = false;
                    //walk.Enabled = false;
                    //walk.Loop = true;
                    //walk.AddTime(1.0f / 90.0f);
                    break;
            }

        }

        private void freeBone(String boneName, Quaternion orientation)
        {
            Bone bone = Entity.Skeleton.GetBone(boneName);

            bone.SetManuallyControlled(true);
            bone.InheritOrientation = false;

            bone.ResetOrientation();
            bone.SetOrientation(orientation.w, orientation.x, orientation.y, orientation.z);
            bone.SetInitialState();
        }

        public void freeBodyParts(int i, int j)
        {
            Entity.Skeleton.BlendMode = SkeletonAnimationBlendMode.ANIMBLEND_CUMULATIVE;

            Quaternion q = Quaternion.IDENTITY;
            Quaternion q2 = new Quaternion();
            Vector3 xAxis = Vector3.UNIT_SCALE, yAxis = Vector3.UNIT_SCALE, zAxis = Vector3.UNIT_SCALE;
            q.FromAngleAxis(new Degree(90), new Vector3(0, 0, -1));
            q.ToAxes(out xAxis, out yAxis, out zAxis);
            q2.FromAngleAxis(new Degree(110).ValueRadians, xAxis);
            Quaternion q3 = q *q2;

            //Quaternion q = new Quaternion(0.9779778, 0.06283262, 0.1987799, 0.009900102);
            freeBone("Humerus.L", q3);

            q.FromAngleAxis(new Degree(90), new Vector3(0, 0, 1));
            q.ToAxes(out xAxis, out yAxis, out zAxis);
            q2.FromAngleAxis(new Degree(110).ValueRadians, xAxis);
            q3 = q * q2;
            freeBone("Humerus.R", q3);



            q.FromAngleAxis(new Degree(90), new Vector3(0, 0, -1));
            q2.FromAngleAxis(new Degree(45), new Vector3(0, -1, 0));

            q3 = q * q2;

            freeBone("Ulna.L", q3);

            q.FromAngleAxis(new Degree(90), new Vector3(0, 0, 1));
            q2.FromAngleAxis(new Degree(45), new Vector3(0, 1, 0));

            q3 = q * q2;

            freeBone("Ulna.R", q3);

            q.FromAngleAxis(new Degree(0), new Vector3(0,1,0));
		    freeBone("Chest",q);
            freeBone("Stomach", q);


            q.FromAngleAxis(new Degree(180), new Vector3(1,0,0));	 	
            q2.FromAngleAxis(new Degree(180), new Vector3(0,1,0));
            freeBone("Thigh.L",q*q2);
            freeBone("Thigh.R",q*q2);

            freeBone("Calf.L",q*q2);
            freeBone("Calf.R",q*q2);
		

            //q.FromAngleAxis(new Degree(180),new Vector3(1,0,0));	 	
            //q2.FromAngleAxis(new Degree(180),new Vector3(0,1,0));
            //q3 = q2 * q;

            //bone = Entity.Skeleton.GetBone("Thigh.L");

            //bone = Entity.Skeleton.GetBone("Ulna.L");
            //bone.SetManuallyControlled(true);
            //bone.InheritOrientation = false;
            //bone.ResetOrientation();

            //bone.SetOrientation(q3.w, q3.x, q3.y, q3.z);

            //bone.SetInitialState();
            //bone = Entity.Skeleton.GetBone("Calf.L");
            //bone.SetOrientation(q3.w, q3.x, q3.y, q3.z);

            //Animation a = Entity.Skeleton.GetAnimation("Dance");

            //a.DestroyNodeTrack(Entity.Skeleton.GetBone("Humerus.L").Handle);// mBodyEnt->getSkeleton()->getBone("Ulna.L")->getHandle());
            //a.DestroyNodeTrack(Entity.Skeleton.GetBone("Thigh.L").Handle);//anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Ulna.R")->getHandle());
            //a.DestroyNodeTrack(Entity.Skeleton.GetBone("Calf.L").Handle);//anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Humerus.L")->getHandle());
            ////anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Humerus.R")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Stomach")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Chest")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Thigh.L")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Thigh.R")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Calf.L")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Calf.R")->getHandle());
            //anim->destroyNodeTrack(mBodyEnt->getSkeleton()->getBone("Root")->getHandle());
        }

            	//void setupBone(const String& name,const Ogre::Quaternion& q)
    //{
    //    Ogre::Bone* bone = mBodyEnt->getSkeleton()->getBone(name);
    //    bone->setManuallyControlled(true);
    //    bone->setInheritOrientation(false);
		
    //    bone->resetOrientation();
    //    bone->setOrientation(q);
	
    //    bone->setInitialState();
    //}

    //        Ogre::Quaternion q = Quaternion::IDENTITY;
    //    Quaternion q2,q3;
    //    Vector3 xAxis,yAxis,zAxis;
    //    q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,-1));
    //    q.ToAxes(xAxis,yAxis,zAxis);
    //    q2.FromAngleAxis(Ogre::Degree(90),xAxis);
    //    setupBone("Humerus.L",q*q2);
    //    q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,1));
    //    q.ToAxes(xAxis,yAxis,zAxis);
    //    q2.FromAngleAxis(Ogre::Degree(90),xAxis);
    //    setupBone("Humerus.R",q*q2);
		
    //    q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,-1));	 
    //    q2.FromAngleAxis(Ogre::Degree(45),Vector3(0,-1,0));
		
    //    setupBone("Ulna.L",q*q2);

    //    q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,1));	 	
    //    setupBone("Ulna.R",q*q2.Inverse());
    //    }

        #endregion

        #region Callbacki zmiany stanu postaci wynikających z Newtona

        public void BodyTransformCallback(Body sender, Quaternion orientation, Vector3 position, int threadIndex)
        {
            Node.Position = position;
            Node.Orientation = Orientation;
        }

        public void BodyForceCallback(Body body, float timeStep, int threadIndex)
        {
            Vector3 force = (Velocity - Body.Velocity * new Vector3(1, 0, 1)) * BodyMass * 60.0f;
            //System.Console.WriteLine(force.ToString());
            Body.AddForce(force);
        }

        #endregion
    }
}
